<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket 多连接测试客户端</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #f5f5f5;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        .header {
            background: #2c3e50;
            color: white;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 20px;
        }
        .controls {
            background: white;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 20px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .control-group {
            display: flex;
            align-items: center;
            gap: 15px;
            margin-bottom: 15px;
            flex-wrap: wrap;
        }
        .control-group:last-child {
            margin-bottom: 0;
        }
        .input-group {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .input-group label {
            font-weight: bold;
            color: #2c3e50;
            min-width: 100px;
        }
        .input-group input {
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 14px;
            width: 80px;
        }
        .button {
            background: #3498db;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            margin: 5px;
            font-size: 14px;
        }
        .button:hover {
            background: #2980b9;
        }
        .button.disconnect {
            background: #e74c3c;
        }
        .button.disconnect:hover {
            background: #c0392b;
        }
        .status {
            display: inline-block;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 12px;
            font-weight: bold;
        }
        .status.connected {
            background: #2ecc71;
            color: white;
        }
        .status.disconnected {
            background: #e74c3c;
            color: white;
        }
        .status.connecting {
            background: #f39c12;
            color: white;
        }
        .connections {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
            gap: 20px;
        }
        .connection-card {
            background: white;
            border-radius: 8px;
            padding: 15px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .connection-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
            padding-bottom: 10px;
            border-bottom: 1px solid #eee;
        }
        .connection-title {
            font-weight: bold;
            color: #2c3e50;
        }
        .message-log {
            height: 200px;
            overflow-y: auto;
            border: 1px solid #ddd;
            padding: 10px;
            background: #f8f9fa;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            white-space: pre-wrap;
            text-align: left;
        }
        .message-item {
            margin-bottom: 5px;
            padding: 2px 0;
            text-align: left;
            word-wrap: break-word;
            word-break: break-all;
        }
        .message-time {
            color: #666;
            font-size: 11px;
            display: inline-block;
            min-width: 80px;
        }
        .message-content {
            color: #333;
            display: inline-block;
            vertical-align: top;
            max-width: calc(100% - 90px);
        }
        .stats {
            background: white;
            padding: 20px;
            border-radius: 8px;
            margin-top: 20px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
        }
        .stat-item {
            text-align: center;
            padding: 15px;
            background: #ecf0f1;
            border-radius: 4px;
        }
        .stat-value {
            font-size: 24px;
            font-weight: bold;
            color: #2c3e50;
        }
        .stat-label {
            color: #7f8c8d;
            font-size: 14px;
        }
        .clear-logs {
            background: #95a5a6;
            color: white;
            border: none;
            padding: 5px 10px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
        }
        .clear-logs:hover {
            background: #7f8c8d;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>WebSocket 多连接测试客户端</h1>
            <p>基于模板: ws://127.0.0.1:13333/wsRouter/cjroot/test2/111/111/111/空闲</p>
        </div>

        <div class="controls">
            <div class="control-group">
                <div class="input-group">
                    <label for="connectionCount">连接数量:</label>
                    <input type="number" id="connectionCount" value="10" min="1" max="50">
                    <button class="button" onclick="generateConnections()">生成连接</button>
                </div>
                <div class="input-group">
                    <label for="baseUrl">基础URL:</label>
                    <input type="text" id="baseUrl" value="ws://127.0.0.1:13333/wsRouter/cjroot" style="width: 300px;">
                </div>
            </div>
            <div class="control-group">
                <button class="button" onclick="connectAll()">连接所有</button>
                <button class="button disconnect" onclick="disconnectAll()">断开所有</button>
                <button class="button" onclick="sendTestMessage()">发送测试消息</button>
                <button class="clear-logs" onclick="clearAllLogs()">清空所有日志</button>
            </div>
        </div>

        <div class="stats">
            <div class="stats-grid">
                <div class="stat-item">
                    <div class="stat-value" id="connectedCount">0</div>
                    <div class="stat-label">已连接</div>
                </div>
                <div class="stat-item">
                    <div class="stat-value" id="totalMessages">0</div>
                    <div class="stat-label">总消息数</div>
                </div>
                <div class="stat-item">
                    <div class="stat-value" id="avgLatency">0ms</div>
                    <div class="stat-label">平均延迟</div>
                </div>
                <div class="stat-item">
                    <div class="stat-value" id="uptime">00:00:00</div>
                    <div class="stat-label">运行时间</div>
                </div>
            </div>
        </div>

        <div class="connections" id="connectionsContainer">
            <!-- 连接卡片将在这里动态生成 -->
        </div>
    </div>

    <script>
        class WebSocketManager {
            constructor() {
                this.connections = new Map();
                this.totalMessages = 0;
                this.startTime = Date.now();
                this.latencies = [];
                this.connectionConfigs = [];
                
                // 初始化默认连接配置
                this.generateConnectionConfigs(10);
                this.init();
                this.startStatsUpdate();
            }

            generateConnectionConfigs(count) {
                const baseUrl = document.getElementById('baseUrl')?.value || 'ws://127.0.0.1:13333/wsRouter/cjroot';
                this.connectionConfigs = [];
                
                for (let i = 1; i <= count; i++) {
                    this.connectionConfigs.push({
                        id: `test${i}`,
                        url: `${baseUrl}/test${i}/111/111/111/空闲`
                    });
                }
            }

            init() {
                this.createConnectionCards();
            }

            createConnectionCards() {
                const container = document.getElementById('connectionsContainer');
                container.innerHTML = ''; // 清空现有内容
                
                this.connectionConfigs.forEach(config => {
                    const card = document.createElement('div');
                    card.className = 'connection-card';
                    card.innerHTML = `
                        <div class="connection-header">
                            <div class="connection-title">${config.id}</div>
                            <div>
                                <span class="status disconnected" id="status-${config.id}">未连接</span>
                                <button class="button" onclick="wsManager.connect('${config.id}')">连接</button>
                                <button class="button disconnect" onclick="wsManager.disconnect('${config.id}')">断开</button>
                                <button class="clear-logs" onclick="wsManager.clearLog('${config.id}')">清空</button>
                            </div>
                        </div>
                        <div class="connection-url" style="font-size: 12px; color: #666; margin-bottom: 10px;">
                            ${config.url}
                        </div>
                        <div class="message-log" id="log-${config.id}"></div>
                    `;
                    container.appendChild(card);
                });
            }

            connect(connectionId) {
                const config = this.connectionConfigs.find(c => c.id === connectionId);
                if (!config) return;

                if (this.connections.has(connectionId)) {
                    this.disconnect(connectionId);
                }

                this.updateStatus(connectionId, 'connecting', '连接中...');
                this.log(connectionId, `正在连接到: ${config.url}`);

                const ws = new WebSocket(config.url);
                const connectionData = {
                    ws: ws,
                    config: config,
                    messageCount: 0,
                    connectTime: Date.now()
                };

                ws.onopen = () => {
                    this.updateStatus(connectionId, 'connected', '已连接');
                    this.log(connectionId, '✅ WebSocket 连接已建立');
                    this.updateStats();
                };

                ws.onmessage = (event) => {
                    connectionData.messageCount++;
                    this.totalMessages++;
                    
                    let messageData;
                    try {
                        messageData = JSON.parse(event.data);
                    } catch (e) {
                        messageData = event.data;
                    }
                    
                    this.log(connectionId, `📨 收到消息: ${JSON.stringify(messageData, null, 2)}`);
                    this.updateStats();
                };

                ws.onerror = (error) => {
                    this.log(connectionId, `❌ 连接错误: ${error.message || '未知错误'}`);
                    this.updateStatus(connectionId, 'disconnected', '连接错误');
                };

                ws.onclose = (event) => {
                    this.log(connectionId, `🔌 连接已关闭 (代码: ${event.code}, 原因: ${event.reason || '未知'})`);
                    this.updateStatus(connectionId, 'disconnected', '已断开');
                    this.connections.delete(connectionId);
                    this.updateStats();
                };

                this.connections.set(connectionId, connectionData);
            }

            disconnect(connectionId) {
                const connectionData = this.connections.get(connectionId);
                if (connectionData && connectionData.ws) {
                    connectionData.ws.close();
                    this.log(connectionId, '🔌 主动断开连接');
                }
            }

            connectAll() {
                this.connectionConfigs.forEach(config => {
                    setTimeout(() => {
                        this.connect(config.id);
                    }, Math.random() * 1000); // 随机延迟避免同时连接
                });
            }

            disconnectAll() {
                this.connections.forEach((_, connectionId) => {
                    this.disconnect(connectionId);
                });
            }

            sendTestMessage() {
                const testMessage = {
                    type: 'test',
                    timestamp: Date.now(),
                    message: 'Hello from WebSocket test client!'
                };

                this.connections.forEach((connectionData, connectionId) => {
                    if (connectionData.ws && connectionData.ws.readyState === WebSocket.OPEN) {
                        connectionData.ws.send(JSON.stringify(testMessage));
                        this.log(connectionId, `📤 发送测试消息: ${JSON.stringify(testMessage)}`);
                    }
                });
            }

            updateStatus(connectionId, status, text) {
                const statusElement = document.getElementById(`status-${connectionId}`);
                if (statusElement) {
                    statusElement.className = `status ${status}`;
                    statusElement.textContent = text;
                }
            }

            log(connectionId, message) {
                const logElement = document.getElementById(`log-${connectionId}`);
                if (logElement) {
                    const timestamp = new Date().toLocaleTimeString();
                    const logEntry = document.createElement('div');
                    logEntry.className = 'message-item';
                    logEntry.innerHTML = `
                        <span class="message-time">[${timestamp}]</span>
                        <span class="message-content">${message}</span>
                    `;
                    logElement.appendChild(logEntry);
                    logElement.scrollTop = logElement.scrollHeight;
                }
            }

            clearLog(connectionId) {
                const logElement = document.getElementById(`log-${connectionId}`);
                if (logElement) {
                    logElement.innerHTML = '';
                }
            }

            clearAllLogs() {
                this.connectionConfigs.forEach(config => {
                    this.clearLog(config.id);
                });
            }

            updateStats() {
                // 更新连接数
                const connectedCount = Array.from(this.connections.values())
                    .filter(conn => conn.ws && conn.ws.readyState === WebSocket.OPEN).length;
                document.getElementById('connectedCount').textContent = connectedCount;

                // 更新总消息数
                document.getElementById('totalMessages').textContent = this.totalMessages;

                // 更新平均延迟（模拟）
                const avgLatency = this.latencies.length > 0 
                    ? Math.round(this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length)
                    : 0;
                document.getElementById('avgLatency').textContent = `${avgLatency}ms`;
            }

            startStatsUpdate() {
                setInterval(() => {
                    // 更新运行时间
                    const uptime = Date.now() - this.startTime;
                    const hours = Math.floor(uptime / 3600000);
                    const minutes = Math.floor((uptime % 3600000) / 60000);
                    const seconds = Math.floor((uptime % 60000) / 1000);
                    document.getElementById('uptime').textContent = 
                        `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
                    
                    this.updateStats();
                }, 1000);
            }
        }

        // 全局函数
        function generateConnections() {
            const count = parseInt(document.getElementById('connectionCount').value);
            if (count < 1 || count > 50) {
                alert('连接数量必须在1-50之间');
                return;
            }
            
            // 先断开所有现有连接
            wsManager.disconnectAll();
            
            // 重新生成连接配置
            wsManager.generateConnectionConfigs(count);
            wsManager.createConnectionCards();
            wsManager.updateStats();
        }

        function connectAll() {
            wsManager.connectAll();
        }

        function disconnectAll() {
            wsManager.disconnectAll();
        }

        function sendTestMessage() {
            wsManager.sendTestMessage();
        }

        function clearAllLogs() {
            wsManager.clearAllLogs();
        }

        // 初始化
        const wsManager = new WebSocketManager();

        // 页面卸载时清理连接
        window.addEventListener('beforeunload', () => {
            wsManager.disconnectAll();
        });
    </script>
</body>
</html>